<script lang="ts"  setup>
import {nextTick, onDeactivated, onUnmounted, reactive, ref} from 'vue'
import 'xterm/css/xterm.css'
import {Terminal} from 'xterm'
import {FitAddon} from 'xterm-addon-fit'
import {Session} from "@/views/applet/ssh/interface";
import store from "@/store";
import SvgIcon from "@/components/svg-icon/index.vue";

const props = defineProps<{session:Session}>()

const websocket = store.useWebSocketStore;

const visible = ref(false);
const terminal = ref<InstanceType<typeof Terminal>>();
const command = ref('');
const isCopy = ref(false);
const clipboard = ref('');
const fitAddon = new FitAddon();
const fontSize = ref<number>(14);
const pty = reactive({
    cols: 80,
    rows: 24
})
const defaultRows = Math.floor((window.innerHeight - 350) / fontSize.value);

terminal.value = new Terminal({
    // allowProposedApi: true,
    fontSize: fontSize.value,
    // rows: defaultRows, //行数
    convertEol: true, //启用时，光标将设置为下一行的开头
    disableStdin: false, //是否应禁用输入
    cursorStyle: "block", //光标样式
    cursorBlink: true, //光标闪烁
    theme: {
        foreground: '#ECECEC', //字体
        background: '#000000', //背景色
        cursor: 'help', //设置光标
    }
})
terminal.value.loadAddon(fitAddon)
terminal.value.onResize(({cols, rows}) => {
    pty.cols = cols;
    pty.rows = rows;
    websocket.shell({id: props.session.id, cmd: 'setup-pty', pty})
})
terminal.value?.onSelectionChange( () => {
    if (terminal.value?.hasSelection()) {
        clipboard.value= terminal.value?.getSelection();
        isCopy.value = false;
    }
});

terminal.value.onData((e: any) => {
    console.log("data", new String(e))
    switch (e) {
            // Ctrl+C
        case '\x03':
            if (clipboard.value && !isCopy.value) {
                isCopy.value = true;
            } else {
                sendCmd('\x03')
            }
            break;
        case '\x16':
            // 粘帖
            command.value += clipboard.value;
            terminal.value?.write(clipboard.value);
            break;
            // 回车发送命令
        case '\r':
            if (command.value) {
                // 返回的内容会携带当前发送的命令，故要删除发送的指令
                const charsToDelete = command.value.length;
                terminal.value?.write(`\x1b[${charsToDelete}D\x1b[K`);// 左移N格并删除到行尾
                sendCmd(command.value)
            } else {
                //\x1b[6~翻页，一页6行, \x1b[20 一页20行
                sendCmd('\x1b[6~');
            }
            break;
        case '\t':
            // sendCmd('\t');
            break
            // Backspace (DEL)
        case '\u007F':
            // if (terminal.value?.buffer.active.cursorX! > 0) {
            if (command.value.length > 0) {
                terminal.value?.write('\b \b')
                command.value = command.value.slice(0, -1);
            } else {
                sendCmd('\b');
            }
            break
            // Up arrow
        case '\u001b[A':
            sendCmd('\u001b[A');
            // if (historyIndex > 0) {
            //     clearCurrentLine();
            //     command.value = history[--historyIndex];
            //     terminal.write(command.value);
            // }
            break;
            // Down arrow
        case '\u001b[B':
            sendCmd('\u001b[B');
            // if (historyIndex < history.length - 1) {
            //     clearCurrentLine();
            //     command.value = history[++historyIndex];
            //     terminal.write(command.value);
            // }
            break;
        case '\u001b[C':
            sendCmd('\u001b[C');
            break
        case ' ':
            if  (command.value) {
                command.value += e
                terminal.value?.write(e)
            } else {
                sendCmd(' ');
            }

            break
            // Print all other characters for demo
        default:
            if ((e >= String.fromCharCode(0x20) && e <= String.fromCharCode(0x7e)) || e >= '\u00a0') {
                command.value += e
                terminal.value?.write(e)
            }
    }
})

const defaultCommand = {
    // clear: {
    //     done: () => {
    //         // terminal.value?.clear()
    //         websocket.send(`${props.session.id}@clear`, "SHELL")
    //     }
    // }
}
const commandsObj = { ...defaultCommand }
// 执行命令 发送消息
const sendCmd = (cmd: string) => {
    cmd = cmd.trim()
    if (cmd.length > 0) {
        if (cmd in commandsObj) {
            (commandsObj as any)[cmd].done();
        } else {
            websocket.shell({id: props.session.id, cmd: cmd})
            // history.push(command.value);
        }
    }
    command.value = ''
}

websocket.registerListener(props.session.id, (rs: any) => {
    terminal.value?.write(rs.data)
})

// 内容全屏显示-窗口大小发生改变时
// function onTerminalResize() {
//     fitAddon.fit();
// }
// window.addEventListener("resize", onTerminalResize)


const onOpen = () => {
    const element  = document.getElementById('terminal') as HTMLElement;
    terminal.value?.open(element)
    // lineHeight.value  = element.clientHeight/terminal.value?.rows!
    const  child = element.children[0].children[1] as HTMLElement;
    if (isFullScreen.value) {
        child.style.setProperty('height', `${window.innerHeight - 32}px`);
    } else {
        child.style.setProperty('height', `${window.innerHeight - 350}px`);
    }
}

const onOpened = () => {
    fitAddon.fit();// 会触发term的onResize事件
    terminal.value?.focus();
}

const isFullScreen = ref(false)
const onFullScreen = () => {
    isFullScreen.value = !isFullScreen.value
    const element  = document.getElementById('terminal') as HTMLElement;
    const  child = element.children[0].children[1] as HTMLElement;
    if (isFullScreen.value) {
        child.style.setProperty('height', `${window.innerHeight - 32}px`);
    } else {
        child.style.setProperty('height', `${window.innerHeight - 350}px`);
    }
    nextTick(() => fitAddon.fit())
}

const show = () => {
    visible.value = true;
}

onUnmounted(() => {
    websocket.shell({id: props.session.id, cmd: 'exit'});
    websocket.removeListener(props.session.id)
    // window.removeEventListener("resize", onTerminalResize)
})

defineExpose({show})
</script>

<template>
    <el-dialog v-model="visible" @open="onOpen"  @opened="onOpened" :fullscreen="isFullScreen"
                :show-close="false" :close-on-click-modal="false" width="60%" align-center destroy-on-close draggable overflow
                style="--el-dialog-padding-primary: 0">
        <template #header="{ close, titleId, titleClass }">
            <div class="dialog-header">
                <div class="dialog-header__title">
                    <el-button link>
                        <template #icon>
                            <svg-icon icon="icon-xterm"/>
                        </template>
                    </el-button>
                    <span :id="titleId" :class="titleClass">
                        X-Terminal
                    </span>
                </div>
                <span>
                    {{ session.host }}({{session.username}})
                </span>
                <div class="dialog-header__btn">
                    <el-button text @click="onFullScreen">
                        <template #icon>
                            <svg-icon :icon="isFullScreen ? 'icon-exit-full-screen' : 'icon-full-screen'" />
                        </template>
                    </el-button>
                    <el-button text @click="close">
                        <template #icon>
                            <svg-icon icon="icon-close"/>
                        </template>
                    </el-button>
                </div>
            </div>
        </template>
        <div id="terminal"/>
    </el-dialog>
</template>
<style scoped>
.xterm ::-webkit-scrollbar {
    width:8px;
    height:8px;
    border-radius:10px;
    background-color:#F5F5F5;
}
.xterm ::-webkit-scrollbar-track
{
    -webkit-box-shadow:inset 0 0 6px rgba(0,0,0,0.3);
    border-radius:10px;
    background-color: #F5F5F5;
}
.xterm ::-webkit-scrollbar-thumb
{
    border-radius:10px;
    -webkit-box-shadow:inset 0 0 6px rgba(0,0,0,.3);
    background-color: #447aff;
}
</style>
<style lang="scss">
.xterm .xterm-viewport {
    border-radius: 0 0 var(--el-dialog-border-radius)  var(--el-dialog-border-radius);
}
</style>

<style lang="scss" scoped>
.dialog-header {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    gap: 16px;
    align-items: center;
    //border-radius: var(--el-dialog-border-radius) var(--el-dialog-border-radius) 0 0;
    //background-color: var(--el-color-primary);

    &__title {
        display: flex;
        align-items: center;

        .el-dialog__title {
            font-weight: lighter;
        }
    }
    &__btn {
        display: flex;
        align-items: center;

        .el-button {
            border-radius: 0;
        }

        .el-button:last-child {
            border-radius: 0 var(--el-dialog-border-radius) 0 0;
        }

        .el-button.is-text:not(.is-disabled):hover {
            background-color: var(--el-fill-color);
        }

        .el-button.is-text:not(.is-disabled):last-child:hover {
            background-color: var(--el-color-danger);
        }

        .el-button + .el-button {
            margin-left: 0;
        }
    }
}

.el-dialog__body {
    //div:first-child {
        //height: calc(100% - var(--component-size));
    //}
}
</style>